home *** CD-ROM | disk | FTP | other *** search
/ PC World 2008 September / PCWorld_2008-09_cd.bin / v cisle / sadanastroju / autocomplete_manager-2.3-fx.xpi / chrome / acmanager.jar / content / rdfUtils.js < prev    next >
Text File  |  2008-03-14  |  25KB  |  590 lines

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: MPL 1.1
  3.  *
  4.  * The contents of this file are subject to the Mozilla Public License Version
  5.  * 1.1 (the "License"); you may not use this file except in compliance with
  6.  * the License. You may obtain a copy of the License at
  7.  * http://www.mozilla.org/MPL/
  8.  *
  9.  * Software distributed under the License is distributed on an "AS IS" basis,
  10.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.  * for the specific language governing rights and limitations under the License.
  12.  *
  13.  * The Original Code is the Autocomplete Manager extension.
  14.  *
  15.  * The Initial Developer of the Original Code is
  16.  * Nikitas Liogkas <nikitas@acm.org>.
  17.  * Portions created by the Initial Developer are Copyright (C) 2005-2008
  18.  * the Initial Developer. All Rights Reserved.
  19.  *
  20.  * Contributor(s): 
  21.  * Version: 2.3
  22.  *
  23.  * ***** END LICENSE BLOCK ***** */
  24.  
  25. // rdfUtils.js
  26. // interfaces with the RDF datasources and retrieves the boookmarks and history items
  27.  
  28. // RDF service and datasources
  29. const acm_rdfService = Components.classes["@mozilla.org/rdf/rdf-service;1"]
  30.             .getService(Components.interfaces.nsIRDFService);
  31.  
  32. const acm_dsHistory   = acm_rdfService.GetDataSource("rdf:history");
  33. const acm_dsBookmarks = acm_rdfService.GetDataSource("rdf:bookmarks"); 
  34.  
  35. const acm_browserHistory = Components.classes["@mozilla.org/browser/global-history;2"]
  36.             .getService(Components.interfaces.nsIBrowserHistory);
  37.  
  38. const acm_ioService = Components.classes["@mozilla.org/network/io-service;1"]
  39.         .getService(Components.interfaces.nsIIOService);
  40.  
  41. // entry properties
  42. const acm_resName = acm_rdfService.GetResource("http://home.netscape.com/NC-rdf#Name"); 
  43. const acm_resURL  = acm_rdfService.GetResource("http://home.netscape.com/NC-rdf#URL"); 
  44. const acm_resHistFirstVisit = acm_rdfService.GetResource("http://home.netscape.com/NC-rdf#FirstVisitDate");
  45. const acm_resHistLastVisit = acm_rdfService.GetResource("http://home.netscape.com/NC-rdf#Date");
  46. const acm_resBookFirstVisit = acm_rdfService.GetResource("http://home.netscape.com/NC-rdf#BookmarkAddDate");
  47. const acm_resBookLastVisit = acm_rdfService.GetResource("http://home.netscape.com/WEB-rdf#LastVisitDate");
  48. const acm_resBookIcon = acm_rdfService.GetResource("http://home.netscape.com/NC-rdf#Icon");
  49. const acm_resVisitCount = acm_rdfService.GetResource("http://home.netscape.com/NC-rdf#VisitCount");  
  50. const acm_resChild = acm_rdfService.GetResource("http://home.netscape.com/NC-rdf#child"); 
  51. const acm_resBookmarkType = acm_rdfService.GetResource("http://www.w3.org/1999/02/22-rdf-syntax-ns#type");
  52.  
  53. // Autocomplete candidate sources; 
  54. // code in acm_Aggregator.{remove,change}Element() assumes none of these is equal to -1!
  55. const ACM_SOURCE_HISTORY   = 0;
  56. const ACM_SOURCE_BOOKMARKS = 1;
  57.  
  58. // holds the bookmarks folders for use in the aggregator
  59. var acm_bookmarkFolders = [];
  60.  
  61. // object for history and bookmark entries
  62. function AutocompleteCandidate(id, title, URL, strippedURL, strippedTitle, webpath, domain, 
  63.                                firstvisit, lastvisit, icon, visitcount, resource, source) {
  64.   // unique id of this entry: order by which it was inserted in the history array; 
  65.   // -1 for bookmarks or history entries entered by observers
  66.   this.id = id;  
  67.  
  68.   // if you change the names of the following, also change the 'onclick' handlers of the history treecols
  69.   this.title = title;
  70.   this.URL = URL;
  71.  
  72.   this.strippedURL = strippedURL;
  73.   this.strippedTitle = strippedTitle;
  74.   this.webpath = webpath;
  75.   this.domain = domain;
  76.  
  77.   this.first_visit = firstvisit;
  78.   this.last_visit = lastvisit;
  79.   this.icon = icon;                // URL of the favicon, "" if none
  80.   this.visit_count = visitcount;
  81.   this.resource = resource;        // the nsIRDFResource of this entry; used to detect duplicate bookmarks
  82.   this.source = source;            // history or bookmark datasource
  83.  
  84.   // what this entry matched against
  85.   //this.matched_against = "";  
  86. }
  87.  
  88. // searches for a bookmark with the given URL
  89. function acm_findBookmark(URL) 
  90. {
  91.   var resURL = acm_rdfService.GetLiteral(URL);
  92.   var resFoundBookmark = acm_dsBookmarks.GetSource(acm_resURL, resURL, true);
  93.  
  94.   if (resFoundBookmark) {
  95.     var nodeName = acm_dsBookmarks.GetTarget(resFoundBookmark, acm_resName, true);
  96.     if (nodeName === null)
  97.       nodeName = acm_rdfService.GetLiteral(""); 
  98.     nodeName.QueryInterface(Components.interfaces.nsIRDFLiteral);
  99.  
  100.     alert("Found " + URL + " with title " + nodeName.Value);  
  101.   }
  102.   else 
  103.     alert(URL + " was not found in the bookmarks file!");
  104. }
  105.  
  106. // searches for a history entry with the given URL
  107. function acm_findHistEntry(URL) 
  108. {
  109.   var resURL = acm_rdfService.GetResource(URL);
  110.   // the source for a history entry is its URL
  111.   var found = acm_dsHistory.GetTarget(resURL, acm_resURL, true);
  112.  
  113.   if (found) {
  114.     var nodeTitle = acm_dsHistory.GetTarget(resURL, acm_resName, true);
  115.     if (nodeTitle === null)
  116.       nodeTitle = acm_rdfService.GetLiteral(""); 
  117.     nodeTitle.QueryInterface(Components.interfaces.nsIRDFLiteral);
  118.  
  119.     alert("Found " + URL + " with title " + nodeTitle.Value);  
  120.   }
  121.   else 
  122.     alert(URL + " was not found in the history file!"); 
  123. }
  124.  
  125. // returns an array with all bookmarks as AutocompleteCandidate objects
  126. function acm_getBookmarks() 
  127. {
  128.   // alternative method of getting the bookmarks
  129.   //var elements = acm_dsBookmarks.GetAllResources();
  130.   //while(elements.hasMoreElements()) {
  131.   //  var item = elements.getNext();
  132.   //  if(acm_dsBookmarks.hasArcOut(item, acm_resURL)) {
  133.   //    var nodeURL = acm_dsBookmarks.GetTarget(item, acm_resURL, true); 
  134.   //    if (nodeURL === null)
  135.   //      nodeURL = acm_rdfService.GetLiteral(""); 
  136.   //    nodeURL.QueryInterface(Components.interfaces.nsIRDFLiteral);
  137.   //  }
  138.   //} 
  139.  
  140.   // start with the root folder, and add subfolders to iterate over
  141.   var resBookmarksRoot = acm_rdfService.GetResource("NC:BookmarksRoot");
  142.   var folders = [resBookmarksRoot];    
  143.   // container service; not available at startup!
  144.   var container = Components.classes["@mozilla.org/rdf/container;1"]
  145.                 .getService(Components.interfaces.nsIRDFContainer); 
  146.  
  147.   while (folders.length > 0) {
  148.     // TOFIX: shifting is expensive!
  149.     container.Init(acm_dsBookmarks, folders.shift());
  150.     var elements = container.GetElements();  // all items in this folder
  151.     while (elements.hasMoreElements()) {
  152.       var item = elements.getNext();
  153.       item.QueryInterface(Components.interfaces.nsIRDFResource); 
  154.       var resItem = acm_rdfService.GetResource(item.Value);
  155.  
  156.       // get this item's type
  157.       var nodeType = acm_dsBookmarks.GetTarget(resItem, acm_resBookmarkType, true);
  158.       nodeType.QueryInterface(Components.interfaces.nsIRDFResource);
  159.  
  160.       // bookmark folder; add it to the list of folders 
  161.       if (nodeType.Value === "http://home.netscape.com/NC-rdf#Folder") {
  162.     folders.push(item);  
  163.         acm_bookmarkFolders.push(resItem);
  164.       }
  165.  
  166.       // regular bookmark
  167.       else if (nodeType.Value === "http://home.netscape.com/NC-rdf#Bookmark") {
  168.     var nodeName = acm_dsBookmarks.GetTarget(resItem, acm_resName, true);
  169.         if (nodeName === null)
  170.           nodeName = acm_rdfService.GetLiteral(""); 
  171.     nodeName.QueryInterface(Components.interfaces.nsIRDFLiteral);
  172.  
  173.         // strip off common protocols and prefixes, and only keep letters and digits
  174.         var strippedTitle = nodeName.Value.toLowerCase();
  175.         strippedTitle = strippedTitle.replace(acm_nonLetterDigitSpace, "");
  176.  
  177.     var nodeURL = acm_dsBookmarks.GetTarget(resItem, acm_resURL, true);
  178.         if (nodeURL === null)
  179.           nodeURL = acm_rdfService.GetLiteral(""); 
  180.     nodeURL.QueryInterface(Components.interfaces.nsIRDFLiteral);
  181.  
  182.         // decode URL
  183.         var url = nodeURL.Value;
  184.         try {
  185.           url = decodeURI(url);
  186.         }
  187.         catch (e) {
  188.           // if URL is malformed, keep it as is
  189.         } 
  190.  
  191.         // strip off common protocols and prefixes, and only keep letters and digits
  192.         var strippedURL = url.toLowerCase().replace(acm_commonProtocol, "");
  193.         strippedURL = strippedURL.replace(acm_commonPrefix, "");
  194.         strippedURL = strippedURL.replace(acm_nonLetterDigitSpace, ""); 
  195.  
  196.         // to determine whether the URL represents a top-level domain address,
  197.         // check the position of the first slash after the longest possible protocol (https://)
  198.         var domain = false;
  199.         var pos = url.indexOf("/", 8);
  200.         if (pos === -1 || pos === url.length - 1)
  201.           domain = true;
  202.  
  203.         // a URL is a Web path if it ends in a slash, if it is a top-level domain, or
  204.         // if there is no '.' after the last slash
  205.         var webpath = false;
  206.         var lastSlash = url.lastIndexOf("/");
  207.         if (lastSlash === url.length - 1 || domain || url.indexOf(".", lastSlash + 1) === -1) 
  208.           webpath = true;
  209.  
  210.     var nodeFirstVisit = acm_dsBookmarks.GetTarget(resItem, acm_resBookFirstVisit, true);
  211.         if (nodeFirstVisit === null) 
  212.           nodeFirstVisit = acm_rdfService.GetDateLiteral(0); 
  213.         nodeFirstVisit.QueryInterface(Components.interfaces.nsIRDFDate); 
  214.  
  215.     var nodeLastVisit = acm_dsBookmarks.GetTarget(resItem, acm_resBookLastVisit, true);
  216.         if (nodeLastVisit === null) 
  217.           nodeLastVisit = acm_rdfService.GetDateLiteral(0);
  218.         nodeLastVisit.QueryInterface(Components.interfaces.nsIRDFDate);
  219.  
  220.     var nodeIcon = acm_dsBookmarks.GetTarget(resItem, acm_resBookIcon, true);
  221.         if (nodeIcon === null)
  222.           nodeIcon = acm_rdfService.GetLiteral(""); 
  223.     nodeIcon.QueryInterface(Components.interfaces.nsIRDFLiteral);
  224.  
  225.         // find bookmark's visit count from history
  226.         var visit_count = 0;
  227.         var resURL = acm_rdfService.GetResource(nodeURL.Value);
  228.         var found  = acm_dsHistory.GetTarget(resURL, acm_resURL, true);
  229.  
  230.         if (found) {
  231.           var nodeVisitCount = acm_dsHistory.GetTarget(resURL, acm_resVisitCount, true);
  232.           if (nodeVisitCount === null)
  233.             nodeVisitCount = acm_rdfService.GetIntLiteral(0);
  234.           nodeVisitCount.QueryInterface(Components.interfaces.nsIRDFInt);
  235.           visit_count = nodeVisitCount.Value;
  236.         }
  237.  
  238.     var candidate = new AutocompleteCandidate(-1, nodeName.Value, url, strippedURL, strippedTitle,
  239.                             webpath, domain, nodeFirstVisit.Value, nodeLastVisit.Value, 
  240.                             nodeIcon.Value, visit_count, resItem, ACM_SOURCE_BOOKMARKS);
  241.  
  242.     yield candidate;
  243.       }
  244.  
  245.       else if (nodeType.Value === "http://home.netscape.com/NC-rdf#Livemark") 
  246.         ;  // do not add livemarks
  247.     }
  248.   }
  249.  
  250.   yield null;  // return null when done
  251. }
  252.  
  253. // generator: returns history entries one by one as AutocompleteCandidate objects
  254. function acm_getHistoryItems() 
  255. {
  256.   var resHistoryRoot = acm_rdfService.GetResource("NC:HistoryRoot");
  257.   // get the children of the history root, i.e. all the history items
  258.   var elements = acm_dsHistory.GetTargets(resHistoryRoot, acm_resChild, true);
  259.   var entryIndex = 0;
  260.   while(elements.hasMoreElements()) {
  261.     var item = elements.getNext();  
  262.     item.QueryInterface(Components.interfaces.nsIRDFResource);
  263.     // item.Value contains the URL, which is the source for this history entry
  264.     var resItem = acm_rdfService.GetResource(item.Value);
  265.  
  266.     var nodeTitle = acm_dsHistory.GetTarget(resItem, acm_resName, true);
  267.     if (nodeTitle === null) 
  268.       nodeTitle = acm_rdfService.GetLiteral(""); 
  269.     nodeTitle.QueryInterface(Components.interfaces.nsIRDFLiteral);
  270.  
  271.     // strip off common protocols and prefixes, and only keep letters and digits
  272.     var strippedTitle = nodeTitle.Value.toLowerCase();
  273.     strippedTitle = strippedTitle.replace(acm_nonLetterDigitSpace, "");
  274.  
  275.     var nodeURL = acm_dsHistory.GetTarget(resItem, acm_resURL, true);
  276.     if (nodeURL === null) 
  277.       nodeURL = acm_rdfService.GetLiteral(""); 
  278.     nodeURL.QueryInterface(Components.interfaces.nsIRDFLiteral);
  279.  
  280.     // decode URL
  281.     var url = nodeURL.Value;
  282.     try {
  283.       url = decodeURI(url);
  284.     }
  285.     catch (e) {
  286.       // if URL is malformed, keep it as is
  287.     } 
  288.  
  289.     // strip off common protocols and prefixes and only keep letters and digits
  290.     var strippedURL = url.toLowerCase().replace(acm_commonProtocol, "");
  291.     strippedURL = strippedURL.replace(acm_commonPrefix, "");
  292.     strippedURL = strippedURL.replace(acm_nonLetterDigitSpace, ""); 
  293.  
  294.     // to determine whether the URL represents a top domain address,
  295.     // check the position of the first slash after the longest possible protocol (https://)
  296.     var domain = false;
  297.     var pos = url.indexOf("/", 8);
  298.     if (pos === -1 || pos === url.length - 1)
  299.       domain = true;
  300.  
  301.     // a URL is a Web path if it ends in a slash, if it is a top-level domain, or
  302.     // if there is no '.' after the last slash
  303.     var webpath = false;
  304.     var lastSlash = url.lastIndexOf("/");
  305.     if (lastSlash === url.length - 1 || domain || url.indexOf(".", lastSlash + 1) === -1) 
  306.       webpath = true;
  307.  
  308.     var nodeFirstVisit = acm_dsHistory.GetTarget(resItem, acm_resHistFirstVisit, true);
  309.     if (nodeFirstVisit === null)
  310.       nodeFirstVisit = acm_rdfService.GetDateLiteral(0);
  311.     nodeFirstVisit.QueryInterface(Components.interfaces.nsIRDFDate); 
  312.  
  313.     var nodeLastVisit = acm_dsHistory.GetTarget(resItem, acm_resHistLastVisit, true);
  314.     if (nodeLastVisit === null)
  315.       nodeLastVisit = acm_rdfService.GetDateLiteral(0);
  316.     nodeLastVisit.QueryInterface(Components.interfaces.nsIRDFDate);
  317.  
  318.     // find favicon from bookmarks
  319.     var favicon = "";
  320.     var resURL = acm_rdfService.GetLiteral(nodeURL.Value);
  321.     var resBookmark = acm_dsBookmarks.GetSource(acm_resURL, resURL, true);
  322.  
  323.     if (resBookmark) {
  324.       var nodeIcon = acm_dsBookmarks.GetTarget(resBookmark, acm_resBookIcon, true);
  325.       if (nodeIcon === null)
  326.         nodeIcon = acm_rdfService.GetLiteral(""); 
  327.       nodeIcon.QueryInterface(Components.interfaces.nsIRDFLiteral);
  328.       favicon = nodeIcon.Value;
  329.     } 
  330.  
  331.     var nodeVisitCount = acm_dsHistory.GetTarget(resItem, acm_resVisitCount, true);
  332.     if (nodeVisitCount === null)
  333.       nodeVisitCount = acm_rdfService.GetIntLiteral(0);
  334.     nodeVisitCount.QueryInterface(Components.interfaces.nsIRDFInt);
  335.  
  336.     var candidate = new AutocompleteCandidate(entryIndex++, nodeTitle.Value, url, 
  337.             strippedURL, strippedTitle, webpath, domain, nodeFirstVisit.Value, 
  338.                         nodeLastVisit.Value, favicon, nodeVisitCount.Value, resItem, ACM_SOURCE_HISTORY);
  339.  
  340.     yield candidate; 
  341.   } 
  342.  
  343.   yield null;  // return null when done
  344. }
  345.  
  346. // returns the info for a bookmark or history entry as an AutocompleteCandidate object
  347. function acm_getEntryInfo(datasource, resItem) 
  348. {
  349.   if (datasource.URI === acm_dsHistory.URI) {
  350.     var nodeTitle = acm_dsHistory.GetTarget(resItem, acm_resName, true);
  351.     if (nodeTitle === null) 
  352.       nodeTitle = acm_rdfService.GetLiteral(""); 
  353.     nodeTitle.QueryInterface(Components.interfaces.nsIRDFLiteral);
  354.  
  355.     // strip off common protocols and prefixes, and only keep letters and digits
  356.     var strippedTitle = nodeTitle.Value.toLowerCase();
  357.     strippedTitle = strippedTitle.replace(acm_nonLetterDigitSpace, "");
  358.  
  359.     var nodeURL = acm_dsHistory.GetTarget(resItem, acm_resURL, true);
  360.     if (nodeURL === null) 
  361.       nodeURL = acm_rdfService.GetLiteral(""); 
  362.     nodeURL.QueryInterface(Components.interfaces.nsIRDFLiteral);
  363.  
  364.     // decode URL
  365.     var url = nodeURL.Value;
  366.     try {
  367.       url = decodeURI(url);
  368.     }
  369.     catch (e) {
  370.       // if URL is malformed, keep it as is
  371.     } 
  372.  
  373.     // strip off common protocols and prefixes and only keep letters and digits
  374.     var strippedURL = url.toLowerCase().replace(acm_commonProtocol, "");
  375.     strippedURL = strippedURL.replace(acm_commonPrefix, "");
  376.     strippedURL = strippedURL.replace(acm_nonLetterDigitSpace, ""); 
  377.  
  378.     // to determine whether the URL represents a top domain address,
  379.     // check the position of the first slash after the longest possible protocol (https://)
  380.     var domain = false;
  381.     var pos = url.indexOf("/", 8);
  382.     if (pos === -1 || pos === url.length - 1)
  383.       domain = true;
  384.  
  385.     // a URL is a Web path if it ends in a slash, if it is a top-level domain, or
  386.     // if there is no '.' after the last slash
  387.     var webpath = false;
  388.     var lastSlash = url.lastIndexOf("/");
  389.     if (lastSlash === url.length - 1 || domain || url.indexOf(".", lastSlash + 1) === -1) 
  390.       webpath = true;
  391.  
  392.     var nodeFirstVisit = acm_dsHistory.GetTarget(resItem, acm_resHistFirstVisit, true);
  393.     if (nodeFirstVisit === null)
  394.       nodeFirstVisit = acm_rdfService.GetDateLiteral(0);
  395.     nodeFirstVisit.QueryInterface(Components.interfaces.nsIRDFDate); 
  396.  
  397.     var nodeLastVisit = acm_dsHistory.GetTarget(resItem, acm_resHistLastVisit, true);
  398.     if (nodeLastVisit === null)
  399.       nodeLastVisit = acm_rdfService.GetDateLiteral(0);
  400.     nodeLastVisit.QueryInterface(Components.interfaces.nsIRDFDate);
  401.  
  402.     // find favicon from bookmarks
  403.     var favicon = "";
  404.     var resURL = acm_rdfService.GetLiteral(nodeURL.Value);
  405.     var resBookmark = acm_dsBookmarks.GetSource(acm_resURL, resURL, true);
  406.  
  407.     if (resBookmark) {
  408.       var nodeIcon = acm_dsBookmarks.GetTarget(resBookmark, acm_resBookIcon, true);
  409.       if (nodeIcon === null)
  410.         nodeIcon = acm_rdfService.GetLiteral(""); 
  411.       nodeIcon.QueryInterface(Components.interfaces.nsIRDFLiteral);
  412.       favicon = nodeIcon.Value;
  413.     }    
  414.  
  415.     var nodeVisitCount = acm_dsHistory.GetTarget(resItem, acm_resVisitCount, true);
  416.     if (nodeVisitCount === null)
  417.       nodeVisitCount = acm_rdfService.GetIntLiteral(0);
  418.     nodeVisitCount.QueryInterface(Components.interfaces.nsIRDFInt);
  419.  
  420.     return new AutocompleteCandidate(-1, nodeTitle.Value, url, strippedURL, strippedTitle,
  421.                                      webpath, domain, nodeFirstVisit.Value, nodeLastVisit.Value, 
  422.                                      favicon, nodeVisitCount.Value, resItem, ACM_SOURCE_HISTORY);     
  423.   } 
  424.   else if (datasource.URI === acm_dsBookmarks.URI) {
  425.     // resItem may represent the URL or the resource of the bookmark
  426.     var resURL = acm_rdfService.GetLiteral(resItem);
  427.     var resBookmark = acm_dsBookmarks.GetSource(acm_resURL, resURL, true);
  428.     if (!resBookmark)
  429.       resBookmark = resItem;
  430.  
  431.     // get this bookmark's type
  432.     var nodeType = acm_dsBookmarks.GetTarget(resBookmark, acm_resBookmarkType, true);
  433.     if (!nodeType)  // maybe it's too early to get the details of this bookmark
  434.       return null;
  435.     nodeType.QueryInterface(Components.interfaces.nsIRDFResource);
  436.  
  437.     // only add regular bookmarks
  438.     if (nodeType.Value !== "http://home.netscape.com/NC-rdf#Bookmark") 
  439.       return null;  
  440.  
  441.     var nodeName = acm_dsBookmarks.GetTarget(resBookmark, acm_resName, true);
  442.     if (nodeName === null)
  443.       nodeName = acm_rdfService.GetLiteral(""); 
  444.     nodeName.QueryInterface(Components.interfaces.nsIRDFLiteral);
  445.  
  446.     // strip off common protocols and prefixes, and only keep letters and digits
  447.     var strippedTitle = nodeName.Value.toLowerCase();
  448.     strippedTitle = strippedTitle.replace(acm_nonLetterDigitSpace, "");
  449.  
  450.     var nodeURL = acm_dsBookmarks.GetTarget(resBookmark, acm_resURL, true);
  451.     if (nodeURL === null)
  452.       nodeURL = acm_rdfService.GetLiteral(""); 
  453.     nodeURL.QueryInterface(Components.interfaces.nsIRDFLiteral);
  454.  
  455.     // decode URL
  456.     var url = nodeURL.Value;
  457.     try {
  458.       url = decodeURI(url);
  459.     }
  460.     catch (e) {
  461.       // if URL is malformed, keep it as is
  462.     } 
  463.  
  464.     // strip off common protocols and prefixes and only keep letters and digits
  465.     var strippedURL = url.toLowerCase().replace(acm_commonProtocol, "");
  466.     strippedURL = strippedURL.replace(acm_commonPrefix, "");
  467.     strippedURL = strippedURL.replace(acm_nonLetterDigitSpace, ""); 
  468.  
  469.     // to determine whether the URL represents a top domain address,
  470.     // check the position of the first slash after the longest possible protocol (https://)
  471.     var domain = false;
  472.     var pos = url.indexOf("/", 8);
  473.     if (pos === -1 || pos === url.length - 1)
  474.       domain = true;
  475.  
  476.     // a URL is a Web path if it ends in a slash, if it is a top-level domain, or
  477.     // if there is no '.' after the last slash
  478.     var webpath = false;
  479.     var lastSlash = url.lastIndexOf("/");
  480.     if (lastSlash === url.length - 1 || domain || url.indexOf(".", lastSlash + 1) === -1) 
  481.       webpath = true;
  482.  
  483.     var nodeFirstVisit = acm_dsBookmarks.GetTarget(resBookmark, acm_resBookFirstVisit, true);
  484.     if (nodeFirstVisit === null) 
  485.       nodeFirstVisit = acm_rdfService.GetDateLiteral(0); 
  486.     nodeFirstVisit.QueryInterface(Components.interfaces.nsIRDFDate); 
  487.  
  488.     var nodeLastVisit = acm_dsBookmarks.GetTarget(resBookmark, acm_resBookLastVisit, true);
  489.     if (nodeLastVisit === null) 
  490.       nodeLastVisit = acm_rdfService.GetDateLiteral(0);
  491.     nodeLastVisit.QueryInterface(Components.interfaces.nsIRDFDate);
  492.  
  493.     var nodeIcon = acm_dsBookmarks.GetTarget(resItem, acm_resBookIcon, true);
  494.     if (nodeIcon === null)
  495.       nodeIcon = acm_rdfService.GetLiteral(""); 
  496.     nodeIcon.QueryInterface(Components.interfaces.nsIRDFLiteral);
  497.  
  498.     // find bookmark's visit count from history
  499.     var visit_count = 0;
  500.     var resURL = acm_rdfService.GetResource(nodeURL.Value);
  501.     var found = acm_dsHistory.GetTarget(resURL, acm_resURL, true);
  502.  
  503.     if (found) {
  504.       var nodeVisitCount = acm_dsHistory.GetTarget(resURL, acm_resVisitCount, true);
  505.       if (nodeVisitCount === null)
  506.         nodeVisitCount = acm_rdfService.GetIntLiteral(0);
  507.       nodeVisitCount.QueryInterface(Components.interfaces.nsIRDFInt);
  508.       visit_count = nodeVisitCount.Value;
  509.     }
  510.  
  511.     return new AutocompleteCandidate(-1, nodeName.Value, url, strippedURL, strippedTitle, 
  512.                                      webpath, domain, nodeFirstVisit.Value, nodeLastVisit.Value, 
  513.                                      nodeIcon.Value, visit_count, resBookmark, ACM_SOURCE_BOOKMARKS); 
  514.   } 
  515.  
  516.   return null;
  517. }
  518.  
  519. // Adds new history entries to the history file; 
  520. // the observers take care of adding these to the candidate list.
  521. // NOTE: this only saves the title and URL right now! When Asserts for history are
  522. // implemented, we will be able to add the other properties as well.
  523. function acm_addNewHistEntries() 
  524. {
  525.   acm_dsHistory.beginUpdateBatch();
  526.   var globalHistory = Components.classes["@mozilla.org/browser/global-history;2"]
  527.                         .getService(Components.interfaces.nsIGlobalHistory2);
  528.  
  529.   for (var i = 0, len = acm_addedHistEntries.length; i < len; i++) {
  530.     var newEntry = acm_addedHistEntries[i];
  531.     var newURI = acm_ioService.newURI(newEntry.URL, null, null);
  532.     globalHistory.addURI(newURI, false, true, null);
  533.     globalHistory.setPageTitle(newURI, newEntry.title);  
  534.  
  535.     var resURL = acm_rdfService.GetResource(newEntry.URL);
  536.  
  537.     // cannot even access the nodes of this entry, let alone change them!
  538.     //var nodeVisitCount = acm_dsHistory.GetTarget(resURL, acm_resVisitCount, true);
  539.     //nodeVisitCount.QueryInterface(Components.interfaces.nsIRDFInt);
  540.     //alert(nodeVisitCount.Value); 
  541.     //acm_dsHistory.Change(resURL, acm_resVisitCount, nodeVisitCount,
  542.     //  acm_rdfService.GetIntLiteral(newEntry.visit_count)); 
  543.  
  544.     // when asserts are implemented for history, this should work!
  545.     //acm_dsHistory.Assert(resURL, acm_resHistFirstVisit, 
  546.     //  acm_rdfService.GetDateLiteral(newEntry.first_visit), true);
  547.     //acm_dsHistory.Assert(resURL, acm_resHistLastVisit, 
  548.     //  acm_rdfService.GetDateLiteral(newEntry.last_visit), true);
  549.     //acm_dsHistory.Assert(resURL, acm_resVisitCount, 
  550.     //  acm_rdfService.GetIntLiteral(newEntry.visit_count), true);  
  551.   }
  552.   acm_dsHistory.endUpdateBatch();
  553.   acm_addedHistEntries = []; 
  554. }
  555.  
  556. // updates edited history entries in the history file
  557. function acm_updateEditedHistEntries() 
  558. {
  559.   // remove the old version of edited entries from the aggregator list
  560.   for (var j = 0, len = acm_editedURLs.length; j < len; j++) {
  561.     for (var i = acm_Aggregator.allCandidates.length - 1; i >= 0; i--) {
  562.       if ( (acm_Aggregator.allCandidates[i].source === ACM_SOURCE_HISTORY) 
  563.            && (acm_Aggregator.allCandidates[i].URL === acm_editedURLs[j]) ) {
  564.         acm_Aggregator.allCandidates.splice(i, 1);
  565.         break;
  566.       }
  567.     } 
  568.   }
  569.  
  570.   // add new version of edited entries to the aggregator list
  571.   // NOTE: an entry may be added twice due to an Assert, but not always!
  572.   // This will be fixed if we figure out how to insert entries using assertions!
  573.   Array.prototype.push.apply(acm_Aggregator.allCandidates, acm_editedHistEntries);
  574.  
  575.   acm_editedHistEntries = []; 
  576.   acm_editedURLs = []; 
  577. }
  578.  
  579. // removes deleted history entries from the history file;
  580. // the observers take care of removing those from the candidate list
  581. function acm_removeDeletedHistEntries() {
  582.   for (var i = 0, len = acm_deletedHistEntries.length; i < len; i++) {
  583.     var deletedEntry = acm_deletedHistEntries[i];
  584.     var uriToDelete = acm_ioService.newURI(deletedEntry.URL, null, null);
  585.     acm_browserHistory.removePage(uriToDelete); 
  586.   }
  587.  
  588.   acm_deletedHistEntries = []; 
  589. }
  590.